package com.example.cachecontroldemo.interceptor;

import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

@Slf4j
public class CacheValidatorInterceptor implements HandlerInterceptor {

    private final Map<String, AbstractCacheControlValidator> cacheControlValidators;

    public CacheValidatorInterceptor(Map<String, AbstractCacheControlValidator> cacheControlValidators) {
        Map<String, AbstractCacheControlValidator> flatCacheMap = new HashMap<>(cacheControlValidators.size());
        for (Map.Entry<String, AbstractCacheControlValidator> entry : cacheControlValidators.entrySet()) {
            for (String path : entry.getKey().split(StrUtil.COMMA)) {
                // Component 注解中使用{},会被当做url，并解析占位符
                String replace = path.trim().replace("[", "{").replace("]", "}");
                flatCacheMap.put(replace, entry.getValue());
            }
        }
        this.cacheControlValidators = flatCacheMap;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (HttpMethod.GET.name().equals(request.getMethod())) {
            Set<String> pathSet = combinePath(handler);
            for (String path : pathSet) {
                log.info("Match Path: {}", path);
                if (cacheControlValidators.containsKey(path)) {
                    AbstractCacheControlValidator controlValidator = cacheControlValidators.get(path);
                    log.info("Match Cache Validator: {}", controlValidator.getClass().getName());
                    boolean validate = controlValidator.validate(request, response);
                    log.info("Match Validate Result: {}", validate);
                    if (validate) {
                        log.info("缓存验证通过，客户端可以使用缓存: {}", request.getRequestURI());
                        ServletOutputStream out = response.getOutputStream();
                        response.setStatus(HttpStatus.NOT_MODIFIED.value());
                        out.flush();
                        return false;
                    }
                }
            }
        }
        return true;
    }

    private Set<String> combinePath(Object handler) {
        if (BooleanUtil.isFalse(handler instanceof HandlerMethod)) {
            return Collections.emptySet();
        }
        String[] requestMappingPaths = ((HandlerMethod) handler).getBeanType().getAnnotation(RequestMapping.class).value();
        String[] methodPaths = ((HandlerMethod) handler).getMethod().getAnnotation(GetMapping.class).path();
        methodPaths = methodPaths.length == 0 ? ((HandlerMethod) handler).getMethod().getAnnotation(GetMapping.class).value() : methodPaths;
        Set<String> pathSet = new HashSet<>(requestMappingPaths.length);
        for (String requestMappingPath : requestMappingPaths) {
            if (methodPaths.length == 0) {
                pathSet.add(requestMappingPath);
                continue;
            }
            for (String methodPath : methodPaths) {
                pathSet.add(requestMappingPath + methodPath);
            }
        }
        return pathSet;
    }

}